#include <iostream>
#include "sigslot/signal.hpp"

void f()
{
    std::cout << "free function\n";
}

struct s
{
    void m()
    {
        std::cout << "member function\n";
    }
    static void sm()
    {
        std::cout << "static member function\n";
    }
};

struct o
{
    void operator()()
    {
        std::cout << "function object\n";
    }
};

int test0()
{
    s d;
    auto lambda = []() { std::cout << "lambda\n"; };

    // declare a signal instance with no arguments
    sigslot::signal<> sig;

    // sigslot::signal will connect to any callable provided it has compatible
    // arguments. Here are diverse examples
    sig.connect(f);
    sig.connect(&s::m, &d);
    sig.connect(&s::sm);
    sig.connect(o());
    sig.connect(lambda);

    // emit a signal
    sig();

    return 0;
}

/* ----------------------------------------------------------- */

template <typename... Args, typename C> constexpr auto overload(void (C::*ptr)(Args...))
{
    return ptr;
}

template <typename... Args> constexpr auto overload(void (*ptr)(Args...))
{
    return ptr;
}

class Light
{
   public:
    void turnLight(int arg, std::string say)
    {
        printf("turnLight arg %d say %s\n", arg, say.c_str());
    }
    void turnLight(int arg0, bool arg1, std::string say)
    {
        printf("turnLight arg %d - %d say %s\n", arg0, arg1, say.c_str());
    }
    void turnLight(int arg0, int arg1, std::string say0, std::string say1)
    {
        printf("turnLight arg %d - %d say %s - %s \n", arg0, arg1, say0.c_str(), say0.c_str());
    }
};

class Switch
{
   public:
    sigslot::signal<int, std::string> click0;
    sigslot::signal<int, bool, std::string> click1;
    sigslot::signal<int, int, std::string, std::string> click2;
};

int test1()
{
    Light mLight;
    Switch mSwitch;

    mSwitch.click0.connect(overload<int, std::string>(&Light::turnLight), &mLight);
    mSwitch.click1.connect(overload<int, bool, std::string>(&Light::turnLight), &mLight);
    mSwitch.click2.connect(overload<int, int, std::string, std::string>(&Light::turnLight), &mLight);

    // emit a signal
    std::string hey = "key from slot";
    mSwitch.click0(1, hey);
    mSwitch.click1(1, true, hey);
    mSwitch.click2(1, 2, hey, hey);

    mSwitch.click0.disconnect_all();
    mSwitch.click1.disconnect_all();
    mSwitch.click2.disconnect_all();

    return 0;
}

int main()
{
    test0();
    test1();

    return 0;
}